﻿using FlyIL.Expression;
using FlyIL.Misc;
using FlyIL.Trace;
using System.Diagnostics;

namespace FlyIL.Optimizer;





class AlterPass : SimplfyRoot
{

    [DebuggerNonUserCode()]
    public override bool IsMatch(Context con, Inst node, ExpByTrace expression = null)
    {
        var inst = node;

        return
            (!con.OptimizerOption.IgnoreOpts.Contains(inst.Opt)     /// 排除要忽略的 运算 
            //&& inst.Opt != Opt.xchg  /// 不是 xchg 
            && inst.Opt != Opt.lea
            && inst.Opt != Opt.mov && inst.Opt != Opt.movzx && inst.Opt != Opt.movsx
            && inst.Opt != Opt.pop

            && !inst.O1.IsReg(con.CodeSp)  /// 不是操作 esp 
            && inst.IsAlter);
    }


    public override void Do(Context con, Inst node, ExpByTrace expression = null)
    {
        /// 如果两个操作数 一样， 没有追踪的必要 
        if (node.O1 != node.O2)
        {
            var exp = con.TraceStrict(con.GetPreviousIfExist(node), ref node.O2);
            if (exp != null && exp.IsValid)
            {
                if (exp.CalcDepth == 0)
                {
                    if (exp.Calculable)
                        node.O2 = Operand.Make(exp.Result, node.O2.ByteSize);
                    else
                    {
                        /// 必须保证宽度的一致性 
                        var no = exp.FinalLeft<Operand>();
                        if (no.ByteSize == node.O2.ByteSize)
                            node.O2 = no;
                    }
                }
            }
        }

        GetSubMatch(con, node)?.Do(con, node, null);

    }

}

internal class AlterNormalPass : AlterPass
{

    public override bool IsMatch(Context con, Inst node, ExpByTrace exp = null)
       => (!node.O1.IsStackValue)
           ;

    /// <summary>
    /// 普通计算
    /// </summary>
    public override void Do(Context con, Inst node, ExpByTrace expression = null)
    {
        var inst = node;
        Expr exp = con.TraceStrict(node, ref inst.O1);
        /// hou zhe deng yi zi sheng 
        if (exp == null || !exp.Intact || (exp.CalcDepth == 0 && exp.FinalLeft<Operand>() == inst.O1))
            return;

        exp.Simplify();
        if (exp.Calculable)
        {
            node.mov(inst.O1, Operand.Make(exp.Result, inst.O1.ByteSize));
            con.RemoveDeadCode(node, ref inst.O1);
        }
        else if (exp.CalcDepth == 0)
        {

            node.mov(inst.O1, exp.FinalLeft<Operand>());
            con.RemoveDeadCode(node, ref inst.O1);
        }


        if (con.OptimizerOption.ExpressionSimply)
        {
            var sim_exp = exp.CalcSimplify(); /// 算法化简 
                                              /// 不存在公式化简
            if (sim_exp == null)
                return;

            /// 化简不会 影响到 原始汇编
            if (con.IsExpIndependent(exp))
                if (con.CompileWithStack(node, exp, sim_exp))
                    node.nop();

        }
    }
}



internal class AlterStackPass : AlterPass
{

    public override bool IsMatch(Context con, Inst node, ExpByTrace exp = null)
       => (node.O1.IsStackValue);

    /// <summary>
    /// 计算栈变量
    /// </summary>
    public override void Do(Context con, Inst node, ExpByTrace expression = null)
    {
        var inst = node;

        Operand op = inst.O1;
        Expr exp = con.TraceStrict(node, ref op);

        if (exp == null)
            return;

        //con.EquilibriumStack(exp);

        var sim_exp = exp.Copy();
        sim_exp.Simplify();
        if (sim_exp.Calculable)
        {
            var pnode = con.Nop_And_Fix_A_StackAccess(node, (int)op.u32, op.ByteSize);
            if (pnode != null)
            {
                ulong val = sim_exp.Result;
                var nnn = Operand.Make(val, op.ByteSize);
                pnode.push(nnn);
            }
        }

        if (con.OptimizerOption.ExpressionSimply)
        {
            sim_exp = sim_exp.CalcSimplify(); /// 算法化简 
                                              /// 不存在公式化简
            if (sim_exp == null)
                return;

            /// 化简不会 影响到 原始汇编
            if (con.IsExpIndependent(exp))
                con.CompileWithStack(node, exp, sim_exp);
        }

    }

}


